package com.ck.ips.controller.program;

import com.ck.common.model.OperationResult;
import com.ck.core.annotation.LoginRequired;
import com.ck.core.annotation.ResourcePermissionRequired;
import com.ck.core.annotation.SysLog;
import com.ck.core.constant.ModuleConstant;
import com.ck.core.constant.MsgConstant;
import com.ck.core.constant.PageConstant;
import com.ck.core.lock.LockConstant;
import com.ck.core.lock.RedisDistributeLock;
import com.ck.core.lock.RedisLock;
import com.ck.ips.controller.BaseController;
import com.ck.ips.service.program.ProgramService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 节目
 *
 * @author linqiang
 * @date 2019-04-29 14:19
 */
@LoginRequired
@RestController
@RequestMapping(value = "/program")
public class ProgramController extends BaseController {
    @Autowired
    private ProgramService programService;
    @Autowired
    private RedisDistributeLock distributeLock;

    /**
     * 节目列表分页查询
     *
     * @param programName   节目名称
     * @param programStatus 节目状态
     * @param programOrigin 节目来源
     * @param deviceGroupId 投放区域（多个英文逗号隔开）
     * @param deviceType    终端类型
     * @param pageNum       当前页
     * @param pageSize      每页条数
     * @param brandId       品牌id
     * @return 列表页面
     */
    @PostMapping(value = "/list")
    public OperationResult listByPage(String programName, Integer programStatus, String programOrigin,
                                      String deviceGroupId, String deviceType, Integer pageNum, Integer pageSize, Integer brandId) {
        pageNum = (pageNum == null ? PageConstant.DEFAULT_PAGE_NUM : pageNum);
        pageSize = (pageSize == null ? PageConstant.DEFAULT_PAGE_SIZE : pageSize);
        return programService.listByPage(programName, programStatus, programOrigin, deviceGroupId, deviceType, pageNum, pageSize, brandId);
    }

    /**
     * 素材JSON信息 （key为分辨率，value为素材信息）
     *
     * @param programVersion   节目版本号
     * @param programName      节目名称
     * @param deviceType       设备类型
     * @param deviceResolution 分辨率
     * @param putinLevel       投放级别
     * @param putinStartTime   投放开始时间
     * @param putinEndTime     投放结束时间
     * @param putinLimit       投放限制
     * @param sourceJson       素材JSON（key:分辨率， value:素材JSON数组）
     * @param deviceCodes      点位（设备序列号哦，多个英文逗号隔开）
     * @param checkPointer     是否检查点位（true检查， false不检查），默认为true
     * @param checkSource      是否检查素材（true检查， false不检查），默认为true， false则为暂存
     * @return OperationResult
     */
    @SysLog(module = ModuleConstant.MODULE_PROGRAM)
    @PostMapping(value = "/save")
    public OperationResult save(String programVersion, String programName, String deviceType, String deviceResolution, Integer putinLevel,
                                String putinStartTime, String putinEndTime, String putinLimit, String sourceJson, String deviceCodes,
                                Boolean checkPointer, Boolean checkSource, Long brandId) {
        return programService.saveBasicInfoAndPointerAndSource(programName, deviceType, deviceResolution, putinLevel, putinStartTime,
                putinEndTime, putinLimit, programVersion, sourceJson, deviceCodes, checkPointer, checkSource, brandId);
    }

    /**
     * 发布节目
     * 发布节目后，如果需要审核，则提示需要审核，不需要审核则回调列表页面
     *
     * @param programVersion 节目版本号
     * @param deviceCodes    点位（设备序列号哦，多个英文逗号隔开）
     * @return OperationResult
     */
    @SysLog(module = ModuleConstant.MODULE_PROGRAM)
    @PostMapping(value = "/publish")
    public OperationResult publish(String programVersion, String deviceCodes) {
        OperationResult result;
        //加锁防止多人同时操作
        try (RedisLock lock = distributeLock.getLock((LockConstant.PROGRAM_PUSH_LOCK_PREFIX + programVersion),
                LockConstant.DEFAULT_TIMEOUT_MILLS, LockConstant.MAX_RETRY_TIMES, LockConstant.RETRY_INTERVAL_TIME_MILLIS)) {
            if (null != lock) {
                result = programService.publish(programVersion, deviceCodes);
            } else {
                result = OperationResult.newValidateFailOperationResult(MsgConstant.SYSTEM_BUSINESS);
            }
        } catch (Exception e) {
            return OperationResult.newSystemErrorOperationResult();
        }
        return result;
    }

    /**
     * 审核通过节目
     *
     * @param programVersion 设备序列号
     * @return OperationResult
     */
    @ResourcePermissionRequired
    @SysLog(module = ModuleConstant.MODULE_PROGRAM)
    @PostMapping(value = "/pass")
    public OperationResult pass(String programVersion) {
        OperationResult result;
        //加锁防止多人同时操作
        try (RedisLock lock = distributeLock.getLock((LockConstant.PROGRAM_PASS_LOCK_PREFIX + programVersion),
                LockConstant.DEFAULT_TIMEOUT_MILLS, LockConstant.MAX_RETRY_TIMES, LockConstant.RETRY_INTERVAL_TIME_MILLIS)) {
            if (null != lock) {
                result = programService.pass(programVersion);
            } else {
                result = OperationResult.newValidateFailOperationResult(MsgConstant.SYSTEM_BUSINESS);
            }
        } catch (Exception e) {
            return OperationResult.newSystemErrorOperationResult();
        }
        return result;
    }

    /**
     * 审核拒绝节目
     * 驳回节目状态修改为‘待发布’
     *
     * @param programVersion 设备序列号（多个以英文逗号隔开）
     * @param rejectReason   拒绝原因
     * @return OperationResult
     */
    @ResourcePermissionRequired
    @SysLog(module = ModuleConstant.MODULE_PROGRAM)
    @PostMapping(value = "/reject")
    public OperationResult reject(String programVersion, String rejectReason) {
        OperationResult result;
        //加锁防止多人同时操作
        try (RedisLock lock = distributeLock.getLock((LockConstant.PROGRAM_REJECT_LOCK_PREFIX + programVersion),
                LockConstant.DEFAULT_TIMEOUT_MILLS, LockConstant.MAX_RETRY_TIMES, LockConstant.RETRY_INTERVAL_TIME_MILLIS)) {
            if (null != lock) {
                result = programService.reject(programVersion, rejectReason);
            } else {
                result = OperationResult.newValidateFailOperationResult(MsgConstant.SYSTEM_BUSINESS);
            }
        } catch (Exception e) {
            return OperationResult.newSystemErrorOperationResult();
        }
        return result;
    }

    /**
     * 审核节目
     *
     * @param programVersion 设备序列号
     * @param optType        操作类型（pass：通过， reject:驳回）
     * @param rejectReason   驳回原因
     * @return OperationResult
     */
    @ResourcePermissionRequired
    @SysLog(module = ModuleConstant.MODULE_PROGRAM)
    @PostMapping(value = "/auth")
    public OperationResult auth(String programVersion, String optType, String rejectReason) {
        OperationResult result;
        //加锁防止多人同时操作
        try (RedisLock lock = distributeLock.getLock((LockConstant.PROGRAM_AUTH_LOCK_PREFIX + programVersion),
                LockConstant.DEFAULT_TIMEOUT_MILLS, LockConstant.MAX_RETRY_TIMES, LockConstant.RETRY_INTERVAL_TIME_MILLIS)) {
            if (null != lock) {
                result = programService.auth(programVersion, optType, rejectReason);
            } else {
                result = OperationResult.newValidateFailOperationResult(MsgConstant.SYSTEM_BUSINESS);
            }
        } catch (Exception e) {
            return OperationResult.newSystemErrorOperationResult();
        }
        return result;
    }


    /**
     * 根据终端类型和分辨率筛选出可选的节目所投放的终端（下拉框）
     *
     * @param deviceCodes 设备序列号（多个英文逗号隔开）
     * @return OperationResult
     */
    @PostMapping(value = "/getDeviceSelect")
    public OperationResult getDeviceSelect(String deviceCodes) {
        return programService.getDeviceSelect(deviceCodes);
    }


    /**
     * 投放终端组（下拉框）
     *
     * @return OperationResult
     */
    @PostMapping(value = "/getDeviceGroupSelect")
    public OperationResult getDeviceGroupSelect() {
        return programService.getDeviceGroupSelect();
    }

    /**
     * 根据终端类型和分辨率筛选出可选的节目列表分页
     * 筛选已创建+未选点的待发布节目
     *
     * @param deviceCodes   设备序列号
     * @param programName   节目名称
     * @param programOrigin 来源
     * @param deviceGroupId 节目已投放的终端组（区域），多个英文逗号隔开
     * @return OperationResult
     */
    @PostMapping(value = "/getProgramByDevices")
    public OperationResult getProgramByDevices(String deviceCodes, String programName, String programOrigin,
                                               String deviceGroupId) {
        return programService.getProgramByDevices(deviceCodes, programName, programOrigin, deviceGroupId);
    }


    /**
     * 从终端发布节目
     * 1.选择点位后，根据设备类型+分辨率 筛选可用的节目（已创建+未选点的待发布节目），选择节目快速发布
     * 2.如果需要审核，则提示需要审核，不需要审核则回调列表页面
     *
     * @param programVersions 节目版本号（多个英文逗号隔开）
     * @param deviceCodes     设备序列号（多个英文逗号隔开）
     * @return OperationResult
     */
    @SysLog(module = ModuleConstant.MODULE_PROGRAM)
    @PostMapping(value = "/fastPublishByProgramAndPointer")
    public OperationResult fastPublishByProgramAndPointer(String programVersions, String deviceCodes) {
        return programService.fastPublishByProgramAndPointer(programVersions, deviceCodes);
    }

    /**
     * 获取节目详情
     *
     * @param programVersion 节目版本号
     * @return OperationResult
     */
    @PostMapping(value = "/getDetail")
    public OperationResult getDetail(String programVersion) {
        return programService.getDetail(null, programVersion);
    }

    /**
     * 获取节目统计信息
     * 统计投放终端组数量，终端数量，素材数量，投放时间，
     * 下发情况（已下发成功：X个终端；发送中：X个终端；发送失败：X个终端）
     * 下载情况（已下载成功：X个终端；下载中：X个终端；下载失败：X个终端）
     *
     * @param programVersion 节目版本号
     * @return OperationResult
     */
    @PostMapping(value = "/getStatisticsInfo")
    public OperationResult getStatisticsInfo(String programVersion) {
        return programService.getStatisticsInfo(programVersion);
    }

    /**
     * 获取节目投放区域，下发详情，下载详情列表分页
     *
     * @param programVersion 节目版本号
     * @param deviceName     设备名称
     * @param deviceCode     设备序列号
     * @param pageNum        当前页
     * @param pageSize       每页条数
     * @return OperationResult
     */
    @PostMapping(value = "/getPutinDevicesByProgram")
    public OperationResult getPutinDevicesByProgram(String programVersion, String deviceName, String deviceCode, Integer pageNum, Integer pageSize) {
        return programService.getDevicesByPage(programVersion, deviceName, deviceCode, pageNum, pageSize);
    }


    /**
     * 增播
     * 只能选择一个终端
     *
     * @param deviceType       设备类型
     * @param deviceResolution 设备分辨率
     * @param deviceCode       设备序列号
     * @param programName      节目名称
     * @param putinLevel       投放级别
     * @param putinLimit       投放限制
     * @param putinStartTime   投放开始时间
     * @param putinEndTime     投放结束时间
     * @param sourceJson       素材JSON信息 （key为分辨率，value为素材信息）
     * @param brandId          品牌id
     * @return OperationResult
     */
    @SysLog(module = ModuleConstant.MODULE_PROGRAM)
    @PostMapping(value = "/added")
    public OperationResult added(String deviceType, String deviceResolution, String deviceCode, String programName,
                                 Integer putinLevel, String putinLimit, String putinStartTime, String putinEndTime, String sourceJson, Long brandId) {
        return programService.added(deviceType, deviceResolution, deviceCode, programName, putinLevel, putinLimit, putinStartTime, putinEndTime, sourceJson, brandId);
    }

    /**
     * 获取终端当前的素材统计信息
     * 待播放的和正在播放的
     *
     * @param deviceCode 设备序列号
     * @return OperationResult
     */
    @PostMapping(value = "/getCurrentSourcesStaticInfoByDeviceCode")
    public OperationResult getCurrentSourcesStaticInfoByDeviceCode(String deviceCode) {
        return programService.getCurrentSourcesStaticInfoByDeviceCode(deviceCode);
    }

    /**
     * 获取终端当前的素材播放列表
     * 待播放的和正在播放的
     *
     * @param deviceCode 设备序列号
     * @param sourceName 素材名称
     * @return OperationResult
     */
    @PostMapping(value = "/getCurrentSourcesByDeviceCode")
    public OperationResult getCurrentSourcesByDeviceCode(String deviceCode, String sourceName) {
        return programService.getCurrentSourcesByDeviceCode(deviceCode, sourceName);
    }

    /**
     * 减播
     * 只能选择一个终端， 减播的素材只是在终端不播放，后台节目中素材不变，因为可能多个终端在播放
     *
     * @param deviceCode 设备序列号
     * @param sourceJson 需要减播的素材数组json字符串（属性包括：节目版本号，素材名称，素材url）
     * @return OperationResult
     */
    @SysLog(module = ModuleConstant.MODULE_PROGRAM)
    @PostMapping(value = "/reduce")
    public OperationResult reduce(String deviceCode, String sourceJson) {
        OperationResult result;
        //加锁防止多人同时操作
        try (RedisLock lock = distributeLock.getLock((LockConstant.PROGRAM_OFF_LINE_LOCK_PREFIX + deviceCode),
                LockConstant.DEFAULT_TIMEOUT_MILLS, LockConstant.MAX_RETRY_TIMES, LockConstant.RETRY_INTERVAL_TIME_MILLIS)) {
            if (null != lock) {
                result = programService.reduce(deviceCode, sourceJson);
            } else {
                result = OperationResult.newValidateFailOperationResult(MsgConstant.SYSTEM_BUSINESS);
            }
        } catch (Exception e) {
            return OperationResult.newSystemErrorOperationResult();
        }
        return result;
    }


    /**
     * 节目下线
     *
     * @param programVersion 节目版本号
     * @return OperationResult
     */
    @SysLog(module = ModuleConstant.MODULE_PROGRAM)
    @PostMapping(value = "/offline")
    public OperationResult offline(String programVersion) {
        OperationResult result;
        //加锁防止多人同时操作
        try (RedisLock lock = distributeLock.getLock((LockConstant.PROGRAM_OFF_LINE_LOCK_PREFIX + programVersion),
                LockConstant.DEFAULT_TIMEOUT_MILLS, LockConstant.MAX_RETRY_TIMES, LockConstant.RETRY_INTERVAL_TIME_MILLIS)) {
            if (null != lock) {
                result = programService.offline(programVersion);
            } else {
                result = OperationResult.newValidateFailOperationResult(MsgConstant.SYSTEM_BUSINESS);
            }
        } catch (Exception e) {
            return OperationResult.newSystemErrorOperationResult();
        }
        return result;
    }

    /**
     * 删除节目
     *
     * @param programVersion 节目版本号
     * @return OperationResult
     */
    @SysLog(module = ModuleConstant.MODULE_PROGRAM)
    @PostMapping(value = "/delete")
    public OperationResult delete(String programVersion) {
        return programService.delete(programVersion);
    }


    /**
     * 复制节目
     * 1.复制基本信息
     * 2.复制素材信息
     * 3.复制点位
     * 4.状态为‘待发布’
     *
     * @param programVersion 节目版本号
     * @return OperationResult
     */
    @SysLog(module = ModuleConstant.MODULE_PROGRAM)
    @PostMapping(value = "/copy")
    public OperationResult copy(String programVersion) {
        return programService.copy(programVersion);
    }

    /**
     * 检查节目素材是否完整
     *
     * @param programVersion 节目版本号
     * @return OperationResult
     */
    @PostMapping(value = "/checkSource")
    public OperationResult checkSource(String programVersion) {
        return programService.checkSource(programVersion);
    }

    /**
     * 检查节目名称是否存在
     *
     * @param programVersion 节目版本号
     * @param programName    节目名称
     * @return OperationResult
     */
    @PostMapping(value = "/checkName")
    public OperationResult checkName(String programVersion, String programName) {
        return programService.checkName(programVersion, programName);
    }

    /**
     * 根据终端获取增播日志列表
     *
     * @param deviceCode 终端序列号
     * @return OperationResult
     */
    @PostMapping(value = "getAddedSourcesByDeviceCode")
    public OperationResult getAddedSourcesByDeviceCode(String deviceCode) {
        return programService.getAddedSourcesByDeviceCode(deviceCode);
    }

    /**
     * 更新节目播放排序
     * @param programVersion 节目版本号
     * @param rank 播放排序
     * @return
     */
    @PostMapping(value = "updateProgramRank")
    public OperationResult getAddedSourcesByDeviceCode(String programVersion, Long rank) {
        return programService.updateProgramRank(programVersion, rank);
    }
}
